""" Mathemetical geometry for games.

    This module contains convenience classes for calculations involving
    geometry, and, to a lesser extent, trigonometry, in ways that are
    convenient for developing two-dimensional games.

    ~~~ Points ~~~

    NOTE: This section was previously called "Vectors", and the classes
    involved were also named "Vector" or something similar. I decided to change
    the name to "point" at the last minute to better express the intended
    purpose; it seemed like a lot of people had a different set of connotations
    related to the word "vector" that were getting in the way of how the class
    was meant to work.

    A "point" is a coordinate on a plane. There are three ways to express
    a point:
    
    Cartesian coordinates:
        A pair of numbers indicating a horizontal distance (x) and
        vertical distance (y) from the origin: (x,y)
        
    Polar coordinates with degrees:
        A pair of numbers indicating an angle (deg) and distance (mag)
        from the origin, with the angle measured in degrees: (deg, mag)
        
    Polar coordinates with radians:
        Same as above, but with the angle measured in radians (rad) rather
        that degrees: (rad, mag)

    There are several classes defined in this module for working with
    points. The point classes can be used to easily find the polar
    coordinates from a set of cartesian coordinates, and vice versa.
    
    The following example shows how a Point object can be used to quickly
    find both the degree and radian angle measurements at a point that is
    located 10 units to the right and and 10 units down.
    
    >>> from math import pi
    >>> from sbak.point import Point
    >>> p = Point(10, 10)
    >>> p.deg
    -45.0
    >>> p.rad
    -0.78539816339744828
    >>> -pi/4
    -0.78539816339744828
    
    Note that positive values for the y axis move _downwards_ since this
    is more useful for making games. That is why the angles in the above
    example come out negative rather than positive.
    
    Also note that point objects in this module retain their previous polar
    coordinate angles when their magnitude is set to 0, or when their
    cartesian coordinates are set to (0,0). This is in contrast to usual
    mathmatical theories, which state that a point (vector) with a magnitude of
    0 must be omnidirectional. This particular behavior of the module is not a
    bug--it is intentional. To find out whether or not a point "should" be
    omnidirectional, simply check to see if its magnitude is 0.
    
    There are 4 variants of the Point class, each one having basically the
    same functionality but with different mutability and presision:
    
    Point          -   Mutable, unhashable, integer precision.
    FPoint         -   Mutable, unhashable, floating-point precision.
    FrozenPoint    -   Immutable, hashable, integer precision.
    FrozenFPoint   -   Immutable, hashable, floating-point precision.
    
    All point classes support the following properties. These can only be
    modified if the class is not a "frozen" class:
    
    Cartesian properties:
    
    x       -   Horizontal distance from the origin to the point.
    y       -   Vertical distance from the origin in a cartesian plane.
    xy      -   The x and y values together as a tuple.
    
    Polar properties:
    
    mag     -   Magnitude (linear distance) from the origin to the point.
    deg     -   Degree angle from the origin to the point.
    rad     -   Radian angle from the origin to the point.
    degmag  -   The degree angle and the magnitude together as a tuple.
    radmag  -   The radian and the magnitude together as a tuple.
    
    NOTE: Radian angles are _always_ measured with floating-point precision,
    even when the point class used uses integer precision. This exception is
    made because radian measure is almost completely useless when only integer
    precision is used, whereas measurements of other kinds of units are often
    very useful even with only integer precision.
    
    Point classes also support the following methods. The argument is a point
    or cartesian (x,y) coordinate.
    
    p1.distance_to( p2 )    -   Returns absolute distance from p1 to p2.
    p1.degrees_to( p2 )     -   Returns direction from p1 to p2 in degrees.
    p1.radians_to( p2 )     -   Returns direction from p1 to p2 in radians.
    
    (See the methods' documentations for more details about how they work.)
    
    Speed Concerns:
    
    All properties of all point classes are optimized towards reading values
    rather than writing values since reading tends to occur far more often than
    writing. 
    
    
    ~~~ Rectangles ~~~
    
    A rectangle ("rect" for short) is a combination of four values:
    x, y, w, and h. ("w" is for "width", and "h" is for "height".) These four
    values together indicate a rectangular region on a plane.
    
    Alternatively, a rectangle can be thought of as two points: The position
    of the top-left corner, and the position of the bottom-right corner
    relative to the top-left--in other words, the "size."
    
    Like points, rects can be represented as instances of a class. Also like
    points, there are two different levels of precision.
    
    Rect            -   Mutable, unhashable, integer precision values.
    FRect           -   Mutable, unhashable, floating-point precision values.
    
    Each of these classes has the following properties:
    
    (NOTE: These properties are named after those of pygame.Rect for
    traditional reasons.)
    
    x           -   Position of the left edge.
    y           -   Position of the top edge.
    w           -   Width (difference between left and right edges).
    width       -   Same as w.
    h           -   Height (difference between top and bottom edges).
    height      -   Same as h.
    left        -   Same as x.
    top         -   Same as y.
    right       -   Position of the right edge.
    bottom      -   Position of the bottom edge.
    pos         -   x and y together as a frozen point.
    size        -   Size of the rectangle; w and h together as a frozen point.
    topleft     -   Same as pos.
    topright    -   Position of the top-right corner as a frozen point.
    bottomleft  -   Position of the bottom-left corner as a frozen point.
    bottomright -   Position of the bottom-right corner as a frozen point.
    center      -   Position of the exact center of the rect as a frozen point.
    midleft     -   Position of the middle of the left edge as a frozen point.
    midright    -   Position of the middle of the right edge as a frozen point.
    midtop      -   Position of the middle of the top edge as a frozen point.
    midbottom   -   Position of the middle of the bottom edge as a frozen
                    point.
                    
    All rect classes support the following methods. These methods do not
    modify the values of the rect, but instead return values as the result of
    their operations:
    
    r.move(d)   -   Create a new rectangle that is the rect `r` moved by the
                    x and y distances indicated by the point `d`.
    
    The following methods are supported do not return values; instead, they
    modify their instance--in other words, they calculate their values
    "in place."
    
    r.move_ip(d)    -   Move `r` by x and y the distances indicated by the
                        point `d`.
                        
    The following methods are useful for collision detection:
    
    r.collidepoint(p)   -   Returns whether or not point `p` is inside rect
                            `r`.
    r.colliderect(r2)   -   Returns whether or not any part of `r2` overlaps
                            with `r`.
                        
    For more information about any of these methods, see their respective
    information. Many of them support multiple calling styles.
    
    More methods will be added in the future as the need arises.
"""


import operator
from math import pi, atan2, hypot, sin, cos, degrees, radians

from point import *
from rect import *


__all__ = [
    'Point',
    'FrozenPoint',
    'FPoint',
    'FrozenFPoint',
    'Rect',
    'FRect',
]